package org.fujay.langchain4jserver.interfaces.api;

import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.fujay.commons.core.result.R;
import org.fujay.langchain4jserver.application.command.CreateKnowledgeBaseCommand;
import org.fujay.langchain4jserver.application.command.UpdateKnowledgeBaseInfoCommand;
import org.fujay.langchain4jserver.application.dto.FileDTO;
import org.fujay.langchain4jserver.application.dto.KnowledgeBaseDTO;
import org.fujay.langchain4jserver.application.dto.KnowledgeBaseIndexStatusDTO;
import org.fujay.langchain4jserver.application.dto.KnowledgeBaseSummaryDTO;
import org.fujay.langchain4jserver.application.service.KnowledgeBaseService;
import org.fujay.langchain4jserver.domain.knowledge.exception.KnowledgeBaseNotFoundException;
import org.fujay.langchain4jserver.domain.knowledge.vo.FileId;
import org.fujay.langchain4jserver.domain.knowledge.vo.KnowledgeBaseId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.util.List;

/**
 * 知识库管理 API
 */
@RestController
@RequestMapping("/api/v1/knowledge-bases")
@RequiredArgsConstructor
public class KnowledgeBaseController {

    private static final Logger log = LoggerFactory.getLogger(KnowledgeBaseController.class);
    private final KnowledgeBaseService knowledgeBaseService;

    /**
     * 创建新的知识库
     *
     * @param request 创建请求，包含名称、描述和嵌入模型ID
     * @return 创建的知识库概要信息 DTO
     */
    @PostMapping
    public R<KnowledgeBaseDTO> createKnowledgeBase(
            @Valid @RequestBody CreateKnowledgeBaseCommand request) {
        return R.ok(knowledgeBaseService.createKnowledgeBase(request));
    }

    /**
     * 获取知识库列表（概要信息）
     *
     * @return 知识库概要信息列表 DTO
     */
    @GetMapping
    public R<List<KnowledgeBaseSummaryDTO>> listKnowledgeBases() {
        return R.ok(knowledgeBaseService.listKnowledgeBases());
    }

    /**
     * 获取知识库详情
     *
     * @param id 知识库ID
     * @return 知识库详细信息 DTO
     */
    @GetMapping("/{id}")
    public R<KnowledgeBaseDTO> getKnowledgeBaseDetail(@PathVariable Long id) {
        KnowledgeBaseId knowledgeBaseId = new KnowledgeBaseId(id);
        KnowledgeBaseDTO dto =
                knowledgeBaseService
                        .getKnowledgeBase(knowledgeBaseId)
                        .orElseThrow(() -> new KnowledgeBaseNotFoundException(knowledgeBaseId));
        return R.ok(dto);
    }

    /**
     * 更新知识库基本信息（名称、描述）
     *
     * @param request 更新请求体
     * @return 操作结果
     */
    @PutMapping
    public R<Void> updateKnowledgeBaseInfo(
            @Valid @RequestBody UpdateKnowledgeBaseInfoCommand request) {
        knowledgeBaseService.updateKnowledgeBaseInfo(request);
        return R.ok();
    }

    /**
     * 删除知识库
     *
     * @param id 知识库ID
     * @return 操作结果
     */
    @DeleteMapping("/{id}")
    public R<Void> deleteKnowledgeBase(@PathVariable Long id) {
        KnowledgeBaseId knowledgeBaseId = new KnowledgeBaseId(id);
        knowledgeBaseService.deleteKnowledgeBase(knowledgeBaseId);
        return R.ok();
    }

    /**
     * 获取知识库索引状态
     *
     * @param id 知识库ID
     * @return 知识库索引状态 DTO
     */
    @GetMapping("/{id}/status")
    public R<KnowledgeBaseIndexStatusDTO> getKnowledgeBaseStatus(@PathVariable Long id) {
        KnowledgeBaseIndexStatusDTO statusDTO =
                knowledgeBaseService.getKnowledgeBaseStatus(new KnowledgeBaseId(id));
        return R.ok(statusDTO);
    }

    /**
     * 列出知识库中的文件
     *
     * @param id 知识库ID
     * @return 文件概要信息列表 DTO
     */
    @GetMapping("/{id}/files")
    public R<List<FileDTO>> listFiles(@PathVariable Long id) {
        KnowledgeBaseId knowledgeBaseId = new KnowledgeBaseId(id);
        List<FileDTO> files = knowledgeBaseService.listFiles(knowledgeBaseId);
        return R.ok(files);
    }

    /**
     * 从知识库中删除文件
     *
     * @param id     知识库ID
     * @param fileId 文件ID
     * @return 操作结果
     */
    @DeleteMapping("/{id}/files/{fileId}")
    public R<Void> deleteFile(@PathVariable Long id, @PathVariable Long fileId) {
        KnowledgeBaseId knowledgeBaseId = new KnowledgeBaseId(id);
        FileId fid = new FileId(fileId);
        knowledgeBaseService.deleteFile(knowledgeBaseId, fid);
        return R.ok();
    }

    // --- Indexing Triggers ---

    /**
     * 手动触发指定文件重新索引
     *
     * @param id     知识库ID
     * @param fileId 文件ID
     * @return 操作结果
     */
    @PostMapping("/{id}/files/{fileId}/index")
    public R<Void> triggerFileIndexing(@PathVariable Long id, @PathVariable Long fileId) {
        knowledgeBaseService.triggerIndexFileAsync(new KnowledgeBaseId(id), new FileId(fileId));
        return R.ok();
    }

    /**
     * 手动触发整个知识库的增量索引（处理 PENDING/FAILED 文件）
     *
     * @param id 知识库ID
     * @return 操作结果
     */
    @PostMapping("/{id}/index")
    public R<Void> triggerKnowledgeBaseIndexing(@PathVariable Long id) {
        knowledgeBaseService.triggerIndexKnowledgeBaseAsync(new KnowledgeBaseId(id));
        return R.ok();
    }

    /**
     * 手动触发知识库重建索引（清空向量库，重新索引所有文件）
     *
     * @param id 知识库ID
     * @return 操作结果
     */
    @PostMapping("/{id}/rebuild")
    public R<Void> triggerKnowledgeBaseRebuild(@PathVariable Long id) {
        knowledgeBaseService.triggerRebuildIndexAsync(new KnowledgeBaseId(id));
        return R.ok();
    }

    /**
     * 上传文件到指定的知识库
     *
     * @param id   知识库ID
     * @param file 上传的文件
     * @return 添加的文件概要信息 DTO
     */
    @PostMapping("/{id}/files")
    public R<FileDTO> uploadFile(@PathVariable Long id, @RequestParam("file") MultipartFile file) {
        KnowledgeBaseId knowledgeBaseId = new KnowledgeBaseId(id);
        try {
            return R.ok(knowledgeBaseService.uploadAndAddFile(knowledgeBaseId, file));
        } catch (IllegalArgumentException e) {
            log.warn("文件处理失败,知识库Id {}: {}", id, e.getMessage());
            return R.fail(e.getMessage());
        } catch (Exception e) {
            log.error("知识库上传文件失败 {}", id, e);
            return R.fail("文件上传失败: " + e.getMessage());
        }
    }
}
